package com.itx.gatewayx.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 内存缓存工具类（Redis替代）
 *
 * @author itx
 */
@Slf4j
@Component
@ConditionalOnProperty(name = "spring.redis.enabled", havingValue = "false")
public class InMemoryUtils {
    
    private final Map<String, CacheObject> CACHE_MAP = new ConcurrentHashMap<>();
    
    /**
     * 缓存基本对象
     *
     * @param key 缓存键
     * @param value 缓存值
     */
    public <T> void setCacheObject(String key, T value) {
        CACHE_MAP.put(key, new CacheObject(value));
    }
    
    /**
     * 缓存基本对象并设置过期时间
     *
     * @param key 缓存键
     * @param value 缓存值
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     */
    public <T> void setCacheObject(String key, T value, long timeout, TimeUnit timeUnit) {
        long expireTime = System.currentTimeMillis() + timeUnit.toMillis(timeout);
        CACHE_MAP.put(key, new CacheObject(value, expireTime));
    }
    
    /**
     * 设置过期时间
     *
     * @param key 缓存键
     * @param timeout 过期时间
     * @return 是否成功
     */
    public boolean expire(String key, long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }
    
    /**
     * 设置过期时间
     *
     * @param key 缓存键
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     * @return 是否成功
     */
    public boolean expire(String key, long timeout, TimeUnit timeUnit) {
        CacheObject cacheObject = CACHE_MAP.get(key);
        if (cacheObject != null) {
            long expireTime = System.currentTimeMillis() + timeUnit.toMillis(timeout);
            cacheObject.setExpireTime(expireTime);
            return true;
        }
        return false;
    }
    
    /**
     * 获取缓存对象
     *
     * @param key 缓存键
     * @return 缓存值
     */
    @SuppressWarnings("unchecked")
    public <T> T getCacheObject(String key) {
        CacheObject cacheObject = CACHE_MAP.get(key);
        if (cacheObject != null) {
            if (cacheObject.isExpired()) {
                CACHE_MAP.remove(key);
                return null;
            }
            return (T) cacheObject.getValue();
        }
        return null;
    }
    
    /**
     * 删除缓存对象
     *
     * @param key 缓存键
     * @return 是否成功
     */
    public boolean deleteObject(String key) {
        return CACHE_MAP.remove(key) != null;
    }
    
    /**
     * 删除集合对象
     *
     * @param collection 集合
     * @return 删除数量
     */
    public long deleteObject(Collection<String> collection) {
        long count = 0;
        for (String key : collection) {
            if (deleteObject(key)) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * 判断是否存在
     *
     * @param key 缓存键
     * @return 是否存在
     */
    public Boolean hasKey(String key) {
        CacheObject cacheObject = CACHE_MAP.get(key);
        if (cacheObject != null && !cacheObject.isExpired()) {
            return true;
        }
        CACHE_MAP.remove(key);
        return false;
    }
    
    /**
     * 匹配键名
     *
     * @param pattern 模式
     * @return 键名集合
     */
    public Collection<String> keys(String pattern) {
        List<String> keys = new ArrayList<>();
        String regex = pattern.replace("*", ".*");
        for (String key : CACHE_MAP.keySet()) {
            if (key.matches(regex) && !CACHE_MAP.get(key).isExpired()) {
                keys.add(key);
            }
        }
        return keys;
    }
    
    /**
     * 缓存对象包装类
     */
    private static class CacheObject {
        private final Object value;
        private long expireTime;
        
        public CacheObject(Object value) {
            this.value = value;
            this.expireTime = -1; // 永不过期
        }
        
        public CacheObject(Object value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
        }
        
        public Object getValue() {
            return value;
        }
        
        public long getExpireTime() {
            return expireTime;
        }
        
        public void setExpireTime(long expireTime) {
            this.expireTime = expireTime;
        }
        
        public boolean isExpired() {
            return expireTime > 0 && System.currentTimeMillis() > expireTime;
        }
    }
} 